//
// Created by Felix on 24-4-24.
//

#ifndef GAZE_USERCONTROLLER_HPP
#define GAZE_USERCONTROLLER_HPP

#include "oatpp/web/server/api/ApiController.hpp"
#include "oatpp/core/macro/component.hpp"
#include "oatpp/core/macro/codegen.hpp"

#include "common.hpp"

#include "service/LocalizationService.hpp"
#include "service/UserService.hpp"

#include "dto/UserCreateDto.hpp"
#include "validate/UserCreateDtoValidate.hpp"

#include "dto/UserUpdateDetailsDto.hpp"
#include "validate/UserUpdateDetailsDtoValidate.hpp"

#include "dto/UserUpdateStatusDto.hpp"
#include "validate/UserUpdateStatusDtoValidate.hpp"

#include "dto/UserUpdatePasswordDto.hpp"
#include "validate/UserUpdatePasswordDtoValidate.hpp"

#include OATPP_CODEGEN_BEGIN(ApiController)

class UserController : public oatpp::web::server::api::ApiController {
public:
    explicit UserController(
            OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)
    ) : oatpp::web::server::api::ApiController(objectMapper) {}

    // 初始化controller，使用ObjectMapper进行序列化及反序列化
    static std::shared_ptr<UserController> createShared(
            OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)
    ) {
        return std::make_shared<UserController>(objectMapper);
    }

private:
    LocalizationService iLocalizationService;
    UserService iUserService;
public:
    ENDPOINT_INFO(createUser) {
        info->addTag("User");
        info->summary = "创建用户";
        info->description = "role 支持 [ ROLE_GUEST , ROLE_ADMIN ]。";
        info->authorization = ""; // <-- 没有这一行，无法声明需要授权
        info->addSecurityRequirement("basic_auth");
        info->addConsumes < Object < UserCreateDto >> ("application/json");
        info->addResponse < Object < MessageDtoComposeUserResponseDto >> (Status::CODE_200, "application/json");
        info->addResponse < Object < MessageDto<> >> (Status::CODE_401,
                "application/json", R"(输出：{"status_code":401,"status":"ERROR","message":"Unauthorized","data":[]})"
        );
        info->addResponse < Object < MessageDto<> >> (Status::CODE_422, "application/json");
    } // Create user
    ENDPOINT("POST", "/api/users", createUser,
             REQUEST(std::shared_ptr<IncomingRequest>, request),
             BODY_DTO(Object < UserCreateDto > , userCreateDto)) {
        userCreateDto->username = trim(userCreateDto->username);
        OATPP_ASSERT_HTTP(
                !userCreateDto->username->empty(),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid username. Must not be empty or too short.",
                        request->getHeader("Accept-Language")
                )
        )
        OATPP_ASSERT_HTTP(
                UserCreateDtoValidate::validateUniqueUsername(iUserService, userCreateDto),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid username. The provided username is already in use.",
                        request->getHeader("Accept-Language")
                )
        )
        OATPP_ASSERT_HTTP(
                UserCreateDtoValidate::validateRequirePassword(userCreateDto),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid password.Password cannot be empty.",
                        request->getHeader("Accept-Language")
                )
        )

        auto message = MessageDtoComposeUserResponseDto::createShared();
        message->status = "OK";
        message->statusCode = 200;
        message->message = "创建成功";
        message->data = iUserService.createUser(userCreateDto);
        return createDtoResponse(Status::CODE_200, message);
    }

    ENDPOINT_INFO(updateUserDetails) {
        info->addTag("User");
        info->summary = "更新用户信息";
        info->description = "role 支持 [ ROLE_GUEST , ROLE_ADMIN ]。<br/>这接口不支持修改密码。";
        info->authorization = ""; // <-- 没有这一行，无法声明需要授权
        info->addSecurityRequirement("basic_auth");
        info->addConsumes < Object < UserUpdateDetailsDto >> ("application/json");
        info->addResponse < Object < MessageDtoComposeUserResponseDto >> (Status::CODE_200, "application/json");
        info->addResponse < Object < MessageDto<> >> (Status::CODE_401,
                "application/json", R"(输出：{"status_code":401,"status":"ERROR","message":"Unauthorized","data":[]})"
        );
        info->addResponse < Object < MessageDto<> >> (Status::CODE_422, "application/json");
    } // Update user details
    ENDPOINT("PUT", "/api/users/{user_id}", updateUserDetails,
             REQUEST(std::shared_ptr<IncomingRequest>, request),
             PATH(Int32, userId, "user_id"),
             BODY_DTO(Object < UserUpdateDetailsDto > , userUpdateDetailsDto)) {
        OATPP_ASSERT_HTTP(
                UserUpdateDetailsDtoValidate::validateRequireUserId(iUserService, userId),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid UserId.UserId is required and must refer to an existing user.",
                        request->getHeader("Accept-Language")
                )
        )
        userUpdateDetailsDto->userId = userId;
        userUpdateDetailsDto->username = trim(userUpdateDetailsDto->username);
        OATPP_ASSERT_HTTP(
                !userUpdateDetailsDto->username->empty(),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid username. Must not be empty or too short.",
                        request->getHeader("Accept-Language")
                )
        )
        OATPP_ASSERT_HTTP(
                UserUpdateDetailsDtoValidate::validateUniqueUsername(iUserService, userUpdateDetailsDto),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid username. The provided username is already in use.",
                        request->getHeader("Accept-Language")
                )
        )
        OATPP_ASSERT_HTTP(
                UserUpdateDetailsDtoValidate::validateRequireStatus(userUpdateDetailsDto),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid Status.The Status field cannot be empty or contain an invalid value.",
                        request->getHeader("Accept-Language")
                )
        )

        auto message = MessageDtoComposeUserResponseDto::createShared();
        message->status = "OK";
        message->statusCode = 200;
        message->message = "修改成功";
        message->data = iUserService.updateUserDetails(userUpdateDetailsDto);
        return createDtoResponse(Status::CODE_200, message);
    }

    ENDPOINT_INFO(updateUserStatus) {
        info->addTag("User");
        info->summary = "修改用户状态";
        info->description = "";
        info->authorization = ""; // <-- 没有这一行，无法声明需要授权
        info->addSecurityRequirement("basic_auth");
        info->addConsumes < Object < UserUpdateStatusDto >> ("application/json");
        info->addResponse < Object < MessageDtoComposeUserResponseDto >> (Status::CODE_200, "application/json");
        info->addResponse < Object < MessageDto<> >> (Status::CODE_401,
                "application/json", R"(输出：{"status_code":401,"status":"ERROR","message":"Unauthorized","data":[]})"
        );
        info->addResponse < Object < MessageDto<> >> (Status::CODE_422, "application/json");
    } // Update user status
    ENDPOINT("PATCH", "/api/users/{user_id}/status", updateUserStatus,
             REQUEST(std::shared_ptr<IncomingRequest>, request),
             PATH(Int32, userId, "user_id"),
             BODY_DTO(Object < UserUpdateStatusDto > , userUpdateStatusDto)) {
        OATPP_ASSERT_HTTP(
                UserUpdateStatusDtoValidate::validateRequireUserId(iUserService, userId),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid UserId.UserId is required and must refer to an existing user.",
                        request->getHeader("Accept-Language")
                )
        )
        userUpdateStatusDto->userId = userId;
        OATPP_ASSERT_HTTP(
                UserUpdateStatusDtoValidate::validateRequireStatus(userUpdateStatusDto),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid Status.The Status field cannot be empty or contain an invalid value.",
                        request->getHeader("Accept-Language")
                )
        )

        auto message = MessageDtoComposeUserResponseDto::createShared();
        message->status = "OK";
        message->statusCode = 200;
        message->message = "修改成功";
        message->data = iUserService.updateUserStatus(userUpdateStatusDto);
        return createDtoResponse(Status::CODE_200, message);
    }

    ENDPOINT_INFO(updateUserPassword) {
        info->addTag("User");
        info->summary = "修改用户密码";
        info->description = "";
        info->authorization = ""; // <-- 没有这一行，无法声明需要授权
        info->addSecurityRequirement("basic_auth");
        info->addConsumes < Object < UserUpdatePasswordDto >> ("application/json");
        info->addResponse < Object < MessageDtoComposeUserResponseDto >> (Status::CODE_200, "application/json");
        info->addResponse < Object < MessageDto<> >> (Status::CODE_401,
                "application/json", R"(输出：{"status_code":401,"status":"ERROR","message":"Unauthorized","data":[]})"
        );
        info->addResponse < Object < MessageDto<> >> (Status::CODE_422, "application/json");
    } // Update user password
    ENDPOINT("PATCH", "/api/users/{user_id}/password", updateUserPassword,
             REQUEST(std::shared_ptr<IncomingRequest>, request),
             PATH(Int32, userId, "user_id"),
             BODY_DTO(Object < UserUpdatePasswordDto > , userUpdatePasswordDto)) {
        OATPP_ASSERT_HTTP(
                UserUpdatePasswordDtoValidate::validateRequireUserId(iUserService, userId),
                Status::CODE_422,
                iLocalizationService.getHttpMessage(
                        "Invalid UserId.UserId is required and must refer to an existing user.",
                        request->getHeader("Accept-Language")
                )
        )
        userUpdatePasswordDto->userId = userId;


        auto message = MessageDtoComposeUserResponseDto::createShared();
        message->status = "OK";
        message->statusCode = 200;
        message->message = "修改成功";
        message->data = iUserService.updateUserPassword(userUpdatePasswordDto);
        return createDtoResponse(Status::CODE_200, message);
    }

    /* ENDPOINT_INFO接口文档， ENDPOINT接口实现 */
    ENDPOINT_INFO(getCurrentUser) {
        info->addTag("User");
        info->summary = "获得当前用户";
        info->description = "";
        info->authorization = ""; // <-- 没有这一行，无法声明需要授权
        info->addSecurityRequirement("basic_auth");
        info->addResponse < Object < MessageDtoComposeUserResponseDto > > (Status::CODE_200, "application/json");
        info->addResponse < Object < MessageDto<> > > (Status::CODE_401,
                "application/json", R"(输出：{"status_code":401,"status":"ERROR","message":"Unauthorized","data":[]})"
        );
        info->addResponse < Object < MessageDto<> > > (Status::CODE_422, "application/json");
    } // Get current users
    ENDPOINT("GET", "/api/users/current", getCurrentUser,
             BUNDLE(Int32, userId)) {
        auto message = MessageDtoComposeUserResponseDto::createShared();
        message->status = "OK";
        message->statusCode = 200;
        message->message = "获得成功";
        message->data = iUserService.getUserById(userId);
        return createDtoResponse(Status::CODE_200, message);
    }

    ENDPOINT_INFO(getUsersById) {
        info->addTag("User");
        info->summary = "获得用户";
        info->description = "";
        info->authorization = ""; // <-- 没有这一行，无法声明需要授权
        info->addSecurityRequirement("basic_auth");
        info->addResponse < Object < MessageDtoComposeUserResponseDto > > (Status::CODE_200, "application/json");
        info->addResponse < Object < MessageDto<> > > (Status::CODE_401,
                "application/json", R"(输出：{"status_code":401,"status":"ERROR","message":"Unauthorized","data":[]})"
        );
        info->addResponse < Object < MessageDto<> > > (Status::CODE_422, "application/json");
    } // Get users by id
    ENDPOINT("GET", "/api/users/{user_id}", getUsersById,
             PATH(Int32, userId, "user_id")) {
        auto message = MessageDtoComposeUserResponseDto::createShared();
        message->status = "OK";
        message->statusCode = 200;
        message->message = "获得成功";
        message->data = iUserService.getUserById(userId);
        return createDtoResponse(Status::CODE_200, message);
    }

    ENDPOINT_INFO(getUsers) {
        info->addTag("User");
        info->summary = "获得用户列表";
        info->description = "";
        info->authorization = ""; // <-- 没有这一行，无法声明需要授权
        info->addSecurityRequirement("basic_auth");
        info->pathParams["page"].addExample("page", oatpp::String("1"));
        info->pathParams["page_size"].addExample("page_size", oatpp::String("10"));
        info->queryParams["keyWords"].required = false;
        info->queryParams["username"].required = false;
        info->queryParams["role"].required = false;
        info->queryParams["status"].required = false;
        info->addResponse < Object < MessageDtoComposePageOfUsers >> (Status::CODE_200, "application/json");
        info->addResponse < Object < MessageDto<> >> (Status::CODE_401,
                "application/json", R"(输出：{"status_code":401,"status":"ERROR","message":"Unauthorized","data":[]})"
        );
        info->addResponse < Object < MessageDto<> >> (Status::CODE_422, "application/json");
    } // Get users
    ENDPOINT("GET", "/api/users/page/{page}/page_size/{page_size}", getUsers,
             PATH(Int32, page),
             PATH(Int32, pageSize, "page_size"),
             QUERY(String, keyWords, "keyWords", ""),
             QUERY(String, username, "username", ""),
             QUERY(String, role, "role", ""),
             QUERY(Int8, status, "status", 1 - 1)) {
        auto queryDto = UserServiceGetAllUsersQueryDto::createShared();
        queryDto->keyWords = keyWords;
        queryDto->username = username;
        queryDto->role = role;
        queryDto->status = status;

        auto message = MessageDtoComposePageOfUsers::createShared();
        message->status = "OK";
        message->statusCode = 200;
        message->message = "获得成功";
        message->data = iUserService.getAllUsers(page, pageSize, queryDto);
        return createDtoResponse(Status::CODE_200, message);
    }
};

#include OATPP_CODEGEN_END(ApiController)

#endif //GAZE_USERCONTROLLER_HPP
